using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Wikey.Extensibility.Classes;
using Wikey.Extensibility.Enums;
using Wikey.Extensibility.Interfaces;
using Wikey.Interfaces.Attributes;
using Wikey.Utilities.Extensions;

namespace Wikey.Transformations.Plugin
{
    public interface ICodeTransformer
    {
        string Link { get; set; }
    }

    [Transformer(Command="Code")]
    public class CodeTransformer : ITransformer, ICodeTransformer
    {
        public CodeTransformer()
        {
            InitializeRenderingConditions();
        }

        public string Command
        {
            get { return this.GetAttributeValue<TransformerAttribute>().Command; }
        }

        public TransformationResult Apply(IExpressionFunction function)
        {
            if( !String.IsNullOrEmpty( function.Value) )
            {
                Link = function.Value;
            }

            SetBrushType();
            return new TransformationResult(TransformationResultType.Html, FindRenderAction()());
        }

        private static Dictionary<Func<ICodeTransformer, bool>, Func<string>> RenderActionList;
        private static bool Initialized = false; 
        private static readonly object LockToken = new object();
        private void InitializeRenderingConditions()
        {
            lock (LockToken)
            {
                if (Initialized)
                    return;

                lock (LockToken)
                {
                    RenderActionList = 
                        new Dictionary<Func<ICodeTransformer, bool>, Func<string>>
                            {
                                {t => String.IsNullOrEmpty(t.Link), NoFilesToRenderException},
                                {t => t.Link.StartsWith("http://"), WebFileRenderer},
                                {t => t.Link.StartsWith("https://"), WebFileRenderer},
                                {t => true, LocalStorageFileRenderer}
                            };

                    Initialized = true;

                }
            }     
        }

        private Func<string> FindRenderAction()
        {
            foreach (var action in RenderActionList)
            {
                if( action.Key(this) )
                {
                    return action.Value;
                }
            }
            return () => String.Empty;
        }

        private static string NoFilesToRenderException()
        {
            throw new ArgumentNullException("File Link is not set!");
        }


        public bool AcceptDirectParameter { get { return true; } set { } }

        public string Link { get; set; }

        public string Code { get; set; }

        private StringBuilder TextBuilder;

        private string Brush { get; set; }

        private void SetBrushType()
        {
            Brush = "class=\"brush: c-sharp;\"";
        }

        private string LocalStorageFileRenderer()
        {
            TextBuilder = new StringBuilder();
            TextBuilder.AppendLine("<pre ").Append(Brush).Append(">");

            using ( var textReader = new StreamReader(this.Link))
            {
                while (!textReader.EndOfStream)
                {
                    TextBuilder.AppendLine(textReader.ReadLine());
                }
            }
            TextBuilder.AppendLine("</pre>");
            return TextBuilder.ToString();
        }

        private string WebFileRenderer()
        {
            TextBuilder = new StringBuilder();
            TextBuilder.AppendLine("<pre ").Append(Brush).Append(">");
            //Factory.Get<ILogger>()
            // Creates an HttpWebRequest with the specified URL. 
            var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(this.Link);
            
            // Sends the HttpWebRequest and waits for the response.            
            var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            
            var receiveStream = myHttpWebResponse.GetResponseStream();
            var encode = Encoding.GetEncoding("utf-8");
            
            // Pipes the stream to a higher level stream reader with the required encoding format. 
            var readStream = new StreamReader(receiveStream, encode);
            
            while (!readStream.EndOfStream) {
                TextBuilder.AppendLine( readStream.ReadLine());
            }

            myHttpWebResponse.Close();
            readStream.Close();

            TextBuilder.AppendLine("</pre>");
            return TextBuilder.ToString();
        }
    }
}